package com.heima.article.job;

import com.alibaba.fastjson.JSON;
import com.heima.article.service.HotArticleService;
import com.heima.common.constants.article.HotArticleConstants;
import com.heima.model.mess.app.ArticleVisitStreamMess;
import com.heima.model.mess.app.UpdateArticleMess;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 定时更新文章分值
 */
@Component
@Slf4j
public class UpdateHotArticleJob {
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    HotArticleService hotArticleService;

    @XxlJob("updateHotArticleJob")
    public ReturnT updateHotArticleHandler(String params) {
        // 1. 获取redis 行为列表中待处理数据
        List<UpdateArticleMess> articleMessList = this.getUpdateArticleMesses();

        if (CollectionUtils.isEmpty(articleMessList)) {
            log.info("热文章分值更新: 太冷清了 未产生任何文章行为 调度任务完成....");
            return ReturnT.SUCCESS;
        }

        // 2. 将数据按照文章分组  进行聚合统计 得到待更新的数据列表
        List<ArticleVisitStreamMess> waitUpdateScoreData = this.getArticleVisitStreamMesses(articleMessList);
        if (CollectionUtils.isEmpty(waitUpdateScoreData)) {
            log.info("热文章分值更新: 太冷清了 未产生任何文章行为 调度任务完成....");
            return ReturnT.SUCCESS;
        }

        // TODO 定时更新文章热度

        // 循环执行更新文章分值方法
        waitUpdateScoreData.forEach(hotArticleService::updateApArticle);


        log.info("热文章分值更新 调度任务完成....");
        return ReturnT.SUCCESS;
    }

    /**
     * 将数据按照文章分组  进行聚合统计
     *
     * @param articleMessList
     * @return
     */
    private List<ArticleVisitStreamMess> getArticleVisitStreamMesses(List<UpdateArticleMess> articleMessList) {

        List<ArticleVisitStreamMess> waitUpdateScoreData = new ArrayList<>();
        // 根据文章Id进行分类
        Map<Long, List<UpdateArticleMess>> listMap = articleMessList.stream().collect(Collectors.groupingBy(UpdateArticleMess::getArticleId));

        //对每个文章进行统计
        listMap.forEach((articleId, messList) -> {
            Optional<ArticleVisitStreamMess> reduce = messList.stream().map(articleMes -> {
                ArticleVisitStreamMess visitStreamMess = new ArticleVisitStreamMess();
                visitStreamMess.setArticleId(articleId);
                switch (articleMes.getType()) {
                    case LIKES:
                        // 设置 点赞数量
                        visitStreamMess.setLike(articleMes.getAdd());
                        break;
                    case VIEWS:
                        // 设置 阅读数量
                        visitStreamMess.setView(articleMes.getAdd());
                        break;
                    case COMMENT:
                        // 设置 评论数量
                        visitStreamMess.setComment(articleMes.getAdd());
                        break;
                    case COLLECTION:
                        // 设置 收藏数量
                        visitStreamMess.setCollect(articleMes.getAdd());
                        break;
                    case UNLIKES:
                        // 设置 不喜欢数量
                        visitStreamMess.setUnlike(articleMes.getAdd());
                        break;
                    case FOLLOW:
                        // 设置 关注数量
                        visitStreamMess.setFollow(articleMes.getAdd());
                        break;
                }
                return visitStreamMess;
            }).reduce((a1, a2) -> {
                a1.setLike(a1.getLike() + a2.getLike());
                a1.setView(a1.getView() + a2.getView());
                a1.setComment(a1.getComment() + a2.getComment());
                a1.setCollect(a1.getCollect() + a2.getCollect());
                a1.setFollow(a1.getFollow() + a2.getFollow());
                a1.setUnlike(a1.getUnlike() + a2.getUnlike());
                return a1;
            });

            // 如果返回结果不为空则为true
            if(reduce.isPresent()){
                // 聚合结果
                ArticleVisitStreamMess visitStreamMess = reduce.get();
                log.info("热点文章 聚合计算结果  ===>{}" , visitStreamMess);
                waitUpdateScoreData.add(visitStreamMess);
            }
        });

        return waitUpdateScoreData;
    }

    // 获取redis 行为列表中待处理数据
    private List<UpdateArticleMess> getUpdateArticleMesses() {
        ListOperations listOperations = redisTemplate.opsForList();

        // 得到当前行为数据数量
        Long size = listOperations.size(HotArticleConstants.HOT_ARTICLE_SCORE_BEHAVIOR_LIST);

        if (size == null)
            return null;

        // 取出redis所有待处理的数据
        List list = redisTemplate.executePipelined((RedisCallback<UpdateArticleMess>) connection -> {
            // 开启管道命令
            connection.openPipeline();
            // 获取所有的数据
            connection.lRange(HotArticleConstants.HOT_ARTICLE_SCORE_BEHAVIOR_LIST.getBytes(), 0, size - 1);
            //删除所有数据
            connection.lTrim(HotArticleConstants.HOT_ARTICLE_SCORE_BEHAVIOR_LIST.getBytes(), size, -1);
            return null;
        });

        if (list.size() > 0) {
            List<String> listData = (List<String>) list.get(0);
            return listData.stream()
                    .map(str -> JSON.parseObject(str, UpdateArticleMess.class))
                    .collect(Collectors.toList());
        }

        return null;
    }
}